/// Modbus 协议相关的常量和函数

/// Modbus 功能码
pub mod function_codes {
    pub const READ_COILS: u8 = 0x01;
    pub const READ_DISCRETE_INPUTS: u8 = 0x02;
    pub const READ_HOLDING_REGISTERS: u8 = 0x03;
    pub const READ_INPUT_REGISTERS: u8 = 0x04;
    pub const WRITE_SINGLE_COIL: u8 = 0x05;
    pub const WRITE_SINGLE_REGISTER: u8 = 0x06;
    pub const WRITE_MULTIPLE_COILS: u8 = 0x0F;
    pub const WRITE_MULTIPLE_REGISTERS: u8 = 0x10;
}

/// Modbus 地址类型
#[derive(Debug, Clone, Copy)]
pub enum AddressType {
    Coil,           // 线圈 (0x)
    DiscreteInput,  // 离散输入 (1x)
    InputRegister,  // 输入寄存器 (3x)
    HoldingRegister, // 保持寄存器 (4x)
}

impl AddressType {
    /// 从地址获取类型
    pub fn from_address(address: u32) -> Option<Self> {
        match address {
            1..=65536 => Some(AddressType::Coil),
            100001..=165536 => Some(AddressType::DiscreteInput),
            300001..=365536 => Some(AddressType::InputRegister),
            400001..=465536 => Some(AddressType::HoldingRegister),
            _ => None,
        }
    }
    
    /// 获取对应的功能码
    pub fn read_function_code(&self) -> u8 {
        match self {
            AddressType::Coil => function_codes::READ_COILS,
            AddressType::DiscreteInput => function_codes::READ_DISCRETE_INPUTS,
            AddressType::InputRegister => function_codes::READ_INPUT_REGISTERS,
            AddressType::HoldingRegister => function_codes::READ_HOLDING_REGISTERS,
        }
    }
    
    /// 获取写入功能码
    pub fn write_function_code(&self, multiple: bool) -> Option<u8> {
        match (self, multiple) {
            (AddressType::Coil, false) => Some(function_codes::WRITE_SINGLE_COIL),
            (AddressType::Coil, true) => Some(function_codes::WRITE_MULTIPLE_COILS),
            (AddressType::HoldingRegister, false) => Some(function_codes::WRITE_SINGLE_REGISTER),
            (AddressType::HoldingRegister, true) => Some(function_codes::WRITE_MULTIPLE_REGISTERS),
            _ => None, // 输入寄存器和离散输入不支持写入
        }
    }
}

/// 将Modbus地址转换为0基址
pub fn to_zero_based_address(address: u32) -> Option<u16> {
    match address {
        1..=65536 => Some((address - 1) as u16),
        100001..=165536 => Some((address - 100001) as u16),
        300001..=365536 => Some((address - 300001) as u16),
        400001..=465536 => Some((address - 400001) as u16),
        _ => None,
    }
}

/// 从0基址转换为Modbus地址
pub fn from_zero_based_address(address: u16, address_type: AddressType) -> u16 {
    match address_type {
        AddressType::Coil => address + 1,
        AddressType::DiscreteInput => address + 100001,
        AddressType::InputRegister => address + 300001,
        AddressType::HoldingRegister => address + 400001,
    }
}